package utils

import (
	"crypto/md5"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/go-resty/resty/v2"
	"go.uber.org/zap"
	"math"
	"math/rand"
	"net"
	"net/http"
	"net/url"
	"project_api/user_web/global"
	"project_api/user_web/models"
	"strconv"
	"strings"
	"time"
)

// AcquireLock 获取 Redis 锁的函数
func AcquireLock(ctx *gin.Context, lockKey string, lockValue string, timeout time.Duration) (bool, error) {
	// 使用 SETNX 设置锁，成功则返回 1，失败返回 0
	result, err := global.RedisDb.SetNX(ctx.Request.Context(), lockKey, lockValue, timeout).Result()
	if err != nil {
		return false, err
	}
	return result, nil
}

// ReleaseLock 释放 Redis 锁的函数
func ReleaseLock(ctx *gin.Context, lockKey string, lockValue string) error {
	// 只有锁的持有者才能释放锁，防止其他程序误释放锁
	// 比较锁值，只有当前值匹配时才删除
	luaScript := `
		if redis.call("get", KEYS[1]) == ARGV[1] then
			return redis.call("del", KEYS[1])
		else
			return 0
		end`
	_, err := global.RedisDb.Eval(ctx.Request.Context(), luaScript, []string{lockKey}, lockValue).Result()
	return err
}

func GenerateSmsCode(width int) string {
	//生成width长度的短信验证码

	numeric := [10]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
	r := len(numeric)
	randGen := rand.New(rand.NewSource(time.Now().UnixNano()))

	var sb strings.Builder
	for i := 0; i < width; i++ {
		fmt.Fprintf(&sb, "%d", numeric[randGen.Intn(r)])
	}
	return sb.String()
}

func GetFreePort() (int, error) {
	addr, err := net.ResolveTCPAddr("tcp", "localhost:0")
	if err != nil {
		return 0, err
	}

	l, err := net.ListenTCP("tcp", addr)
	if err != nil {
		return 0, err
	}
	defer l.Close()
	return l.Addr().(*net.TCPAddr).Port, nil
}

func GetEth0IPv4() (string, error) {
	// 获取所有网络接口
	interfaces, err := net.Interfaces()
	if err != nil {
		return "", err
	}

	// 遍历所有接口
	for _, iface := range interfaces {
		// 查找接口名为 eth0
		if iface.Name == "eth0" {
			// 获取该接口的所有地址
			addrs, err := iface.Addrs()
			if err != nil {
				return "", err
			}

			// 遍历所有地址，查找 IPv4 地址
			for _, addr := range addrs {
				// 地址类型是 IP 地址
				if ipNet, ok := addr.(*net.IPNet); ok && ipNet.IP.To4() != nil {
					return ipNet.IP.String(), nil
				}
			}
		}
	}
	return "", fmt.Errorf("no IPv4 address found for eth0")
}

// AddOssPrefix 增加路径前缀oss域名
func AddOssPrefix(file string) string {
	if file == "" {
		return ""
	}
	// 将反斜杠替换为正斜杠
	file = strings.Replace(file, "\\", "/", -1)
	// 获取资源前缀
	pre := global.ServerConfig.AliOssInfo.Host

	// 如果文件路径没有以 http 开头，拼接资源前缀
	if !strings.HasPrefix(file, "http") {
		return pre + file
	}

	// 如果已经是 http 开头的 URL，直接返回
	return file
}

// ParseHeaderInt 辅助函数：从 Header 中获取整数类型的值，如果无法转换为整数，则返回 0
func ParseHeaderInt(ctx *gin.Context, key string) int32 {
	value := ctx.GetHeader(key)
	if value == "" {
		return 0
	}
	parsedValue, err := strconv.Atoi(value)
	if err != nil {
		return 0
	}
	return int32(parsedValue)
}

func GetAllParams(c *gin.Context) string {
	// 获取所有 GET 参数
	getParamsMap := c.Request.URL.Query() // 获取全部GET参数

	// 获取所有 POST 参数
	postParamsMap := make(map[string]string)
	for key, values := range c.Request.Form {
		// 只取第一个值作为参数值
		postParamsMap[key] = values[0]
	}

	// 合并 GET 和 POST 参数
	allParams := make(map[string]string)

	// 将 GET 参数添加到 allParams
	for key, value := range getParamsMap {
		allParams[key] = value[0] // 取 GET 参数的第一个值
	}

	// 将 POST 参数添加到 allParams
	for key, value := range postParamsMap {
		allParams[key] = value
	}

	// 将合并后的参数转为 JSON 字符串
	requestData, err := json.Marshal(allParams)
	if err != nil {
		return ""
	}

	return string(requestData)
}

// GetClientIP 获取客户端真实IP
func GetClientIP(c *gin.Context) string {
	// 1. 获取 X-Forwarded-For 头部
	xff := c.Request.Header.Get("X-Forwarded-For")
	if xff != "" {
		// 2. 如果 X-Forwarded-For 有多个 IP 地址，通常第一个是客户端的真实 IP
		ips := strings.Split(xff, ",")
		for _, ip := range ips {
			ip = strings.TrimSpace(ip)
			if ip != "unknown" {
				return ip
			}
		}
	}

	// 3. 如果没有 X-Forwarded-For 或无法获取有效 IP，检查 X-Real-IP
	xr := c.Request.Header.Get("X-Real-IP")
	if xr != "" {
		return xr
	}

	// 4. 如果没有 X-Forwarded-For 和 X-Real-IP，使用 REMOTE_ADDR
	ip := c.ClientIP() // gin 框架自带的 ClientIP 方法
	return ip
}

func CommonResponse(ctx *gin.Context, code int, msg string, data interface{}) {
	res := gin.H{
		"code":    code,
		"message": msg,
	}
	if data != nil {
		res["data"] = data
	}

	ctx.JSON(http.StatusOK, res)
}

func Sec2Time(time int64) string {
	// 如果时间为负值或不是有效的数字，直接返回空字符串
	if time < 0 {
		return ""
	}

	// 初始化返回的值
	value := map[string]int{
		"years":   0,
		"days":    0,
		"hours":   0,
		"minutes": 0,
		"seconds": 0,
	}

	// 计算年份
	if time >= 31556926 {
		value["years"] = int(math.Floor(float64(time / 31556926)))
		time = time % 31556926
	}

	// 计算天数
	if time >= 86400 {
		value["days"] = int(math.Floor(float64(time / 86400)))
		time = time % 86400
	}

	// 计算小时
	if time >= 3600 {
		value["hours"] = int(math.Floor(float64(time / 3600)))
		time = time % 3600
	}

	// 计算分钟
	if time >= 60 {
		value["minutes"] = int(math.Floor(float64(time / 60)))
		time = time % 60
	}

	// 剩下的就是秒数
	value["seconds"] = int(time)

	// 构建返回字符串
	result := ""
	if value["years"] > 0 {
		result += fmt.Sprintf("%d年", value["years"])
	}
	if value["days"] > 0 {
		result += fmt.Sprintf("%d天", value["days"])
	}
	if value["hours"] > 0 {
		result += fmt.Sprintf("%d小时", value["hours"])
	}
	if value["minutes"] > 0 {
		result += fmt.Sprintf("%d分", value["minutes"])
	}
	result += fmt.Sprintf("%d秒", value["seconds"])

	return result
}

func SendSmsPart(ctx *gin.Context, phone string, code string) bool {
	// 参数
	host := "https://smsv2.market.alicloudapi.com"
	path := "/sms/sendv2"
	appCode := global.ServerConfig.AliSmsPartInfo.Appcode // 请替换为实际的AppCode
	// 消息内容
	content := "【时光语音】您的验证码是%s。如非本人操作，请忽略本短信"
	content = fmt.Sprintf(content, code)
	// 编码消息内容
	msgContent := url.QueryEscape(content)
	// 构建查询参数
	queryParams := fmt.Sprintf("mobile=%s&content=%s", phone, msgContent)
	// 拼接完整URL
	urlStr := host + path + "?" + queryParams
	// 创建 resty 客户端
	client := resty.New()

	// 发送 GET 请求
	resp, err := client.R().
		SetHeader("Authorization", "APPCODE "+appCode). // 设置请求头
		Get(urlStr)                                     // 发送 GET 请求
	if err != nil {
		zap.S().Errorw("[SendSmsPart] Error sending request:", "msg", err.Error())
		return false
	}

	if resp.IsError() {
		zap.S().Error("[SendSmsPart] Error sending request1:")
		return false
	}

	type SmsPartResponse struct {
		ErrorCode int    `json:"error_code"`
		Reason    string `json:"reason"`
		Result    string `json:"result"`
		Sn        string `json:"sn"`
	}
	var apiResponse SmsPartResponse
	body := resp.Body()
	if err := json.Unmarshal(body, &apiResponse); err != nil {
		zap.S().Errorw("[SendSmsPart] Error parsing response body:", "msg", err.Error())
		return false
	}

	if apiResponse.ErrorCode != 0 {
		zap.S().Errorf("[SendSmsPart] %s", string(body))
		return false
	}

	return true
}

// InArrayByInt 判断元素是否在切片中
func InArrayByInt(element int32, array []int32) bool {
	for _, value := range array {
		if value == element {
			return true
		}
	}
	return false
}

// InArrayByInt 判断元素是否在切片中
func InArrayByString(element string, array []string) bool {
	for _, value := range array {
		if value == element {
			return true
		}
	}
	return false
}

// GetRandomStr 生成随机字符串
func GetRandomStr(length int, special bool) string {
	// 定义基本字符集（字母和数字）
	chars := []string{
		"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k",
		"l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v",
		"w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G",
		"H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R",
		"S", "T", "U", "V", "W", "X", "Y", "Z", "0", "1", "2",
		"3", "4", "5", "6", "7", "8", "9",
	}

	// 如果需要特殊字符，添加特殊字符到字符集
	if special {
		specialChars := []string{
			"!", "@", "#", "|", "/", ";", "%",
			"^", "(", ")", "-", "_", "<", ">", "~", "+", ",", ".",
		}
		chars = append(chars, specialChars...)
	}

	// 初始化随机种子
	rand.Seed(time.Now().UnixNano())

	// 打乱字符集
	rand.Shuffle(len(chars), func(i, j int) {
		chars[i], chars[j] = chars[j], chars[i]
	})

	// 生成随机字符串
	var sb strings.Builder
	for i := 0; i < length; i++ {
		sb.WriteString(chars[rand.Intn(len(chars))])
	}

	return sb.String()
}

// GetBirthdayMsg 获取生日信息的函数
// 获取生日信息的函数
func GetBirthdayMsg(birthday string, typ int) (interface{}, error) {
	// 判断传入的生日字符串是否合法
	if birthday == "" {
		return nil, fmt.Errorf("invalid birthday")
	}
	if typ < 0 || typ > 2 {
		return nil, fmt.Errorf("invalid type, must be 0, 1, or 2")
	}

	// 解析生日字符串
	birthDate, err := time.Parse("2006-01-02", birthday)
	if err != nil {
		return nil, fmt.Errorf("invalid birthday format: %v", err)
	}

	// 获取当前日期
	currentDate := time.Now()

	// 计算年龄
	yearDiff := currentDate.Year() - birthDate.Year()
	monthDiff := int(currentDate.Month()) - int(birthDate.Month())
	dayDiff := currentDate.Day() - birthDate.Day()

	// 如果当前日期还未到达生日，则年龄减去 1
	if monthDiff < 0 || (monthDiff == 0 && dayDiff < 0) {
		yearDiff--
	}

	// 生肖（根据年份）
	animals := []string{"鼠", "牛", "虎", "兔", "龙", "蛇", "马", "羊", "猴", "鸡", "狗", "猪"}
	animalIndex := (birthDate.Year() - 1900) % 12
	animal := animals[animalIndex]

	// 星座判断
	// 星座日期范围，每个星座的起始日期
	signs := []struct {
		Day   int
		Name  string
		Month int
	}{
		{20, "宝瓶座", 1}, {19, "双鱼座", 2}, {21, "白羊座", 3}, {20, "金牛座", 4},
		{21, "双子座", 5}, {22, "巨蟹座", 6}, {23, "狮子座", 7}, {23, "处女座", 8},
		{23, "天秤座", 9}, {24, "天蝎座", 10}, {22, "射手座", 11}, {22, "摩羯座", 12},
	}

	sign := ""
	for i, s := range signs {
		// 判断是否在当前星座范围
		if int(birthDate.Month()) == s.Month && birthDate.Day() >= s.Day {
			sign = s.Name
			break
		}

		// 判断是否在上一个星座范围
		if int(birthDate.Month()) == s.Month && birthDate.Day() < s.Day {
			if i == 0 {
				sign = signs[len(signs)-1].Name
			} else {
				sign = signs[i-1].Name
			}
			break
		}
	}

	// 返回不同类型的生日信息
	switch typ {
	case 0:
		return yearDiff, nil
	case 1:
		return animal, nil
	case 2:
		return sign, nil
	default:
		return nil, fmt.Errorf("invalid type")
	}
}

func GetVipLevelAndImg(userId int32, uType int32) gin.H {
	levelAndImg := gin.H{
		"vip_level": 0,
		"vip_img":   "",
	}
	if userId == 0 || uType == 0 {
		return levelAndImg
	}

	if !InArrayByInt(uType, []int32{1, 2, 3}) {
		return levelAndImg
	}

	var userTotalModel models.UserTotal
	result := global.DB.Where(&models.UserTotal{UserId: userId}).First(&userTotalModel)
	if result.Error != nil {
		return levelAndImg
	}
	if result.RowsAffected == 0 {
		return levelAndImg
	}

	var mizuan int64
	if uType == 1 {
		mizuan = userTotalModel.Gain
	} else {
		mizuan = userTotalModel.Send
	}

	var vipLevel models.Vip

	result = global.DB.
		Where("type = ? AND mizuan <= ?", uType, mizuan).Order("level desc").
		Limit(1).
		Select("level, img").
		First(&vipLevel)
	if result.RowsAffected == 0 {
		return levelAndImg
	}

	levelAndImg["vip_level"] = vipLevel.Level
	levelAndImg["vip_img"] = vipLevel.Img
	return levelAndImg
}

// GetEncryptPassword 加密密码
func GetEncryptPassword(password string, salt string) string {
	// 对密码先 md5 加密
	hash := md5.New()
	hash.Write([]byte(password))
	md5Password := hex.EncodeToString(hash.Sum(nil))

	// 将 md5 密码与盐值拼接，再次 md5 加密
	hash.Reset()
	hash.Write([]byte(md5Password + salt))
	return hex.EncodeToString(hash.Sum(nil))
}
